// -----------------------------------------------------------------------
//   <copyright file="BlockedEndpoint.cs" company="Asynkron AB">
//       Copyright (C) 2015-2025 Asynkron AB All rights reserved
//   </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Concurrent;
using System.Threading.Channels;
using System.Threading.Tasks;

namespace Proto.Remote;

public sealed class BlockedEndpoint : IRemoteEndpoint
{
    private readonly ActorSystem _system;

    public BlockedEndpoint(ActorSystem system)
    {
        _system = system;
    }

    public Channel<RemoteDeliver[]> Outgoing { get; } = Channel.CreateUnbounded<RemoteDeliver[]>();
    public ConcurrentStack<RemoteDeliver[]> OutgoingStash { get; } = new();
    public bool IsActive => false; //will cause the endpoint to be reevaluated every time it is used

    public ValueTask DisposeAsync()
    {
        GC.SuppressFinalize(this);

        return default;
    }

    public void RemoteTerminate(PID watcher, Terminated terminated) => watcher.SendSystemMessage(_system, terminated);

    public void RemoteUnwatch(PID pid, Unwatch unwatch)
    {
    }

    public void RemoteWatch(PID pid, Watch watch) => _system.Root.Send(watch.Watcher,
        new Terminated { Who = pid, Why = TerminatedReason.AddressTerminated });

    public void SendMessage(PID pid, object msg)
    {
        var (message, sender, _) = Proto.MessageEnvelope.Unwrap(msg);

        switch (message)
        {
            case PoisonPill or Stop when sender is not null:
                _system.Root.Send(sender, new Terminated { Who = pid, Why = TerminatedReason.AddressTerminated });

                break;
            default:
                if (sender is not null)
                {
                    _system.Root.Send(sender, new DeadLetterResponse { Target = pid });
                }
                else
                {
                    _system.EventStream.Publish(new DeadLetterEvent(pid, message, sender));
                }

                break;
        }
    }
}